/*
 *   Copyright (c) 2011 Hitachi Data Systems, Inc.
 *
 *   Permission is hereby granted to  this software and associated
 *   documentation files (the "Software"), subject to the terms and
 *   conditions of the Sample Source Code License (SSCL) delivered
 *   with this Software. If you do not agree to the terms and
 *   conditions of the SSCL,
 *
 *     (i)  you must close this file and delete all copies of the
 *          Software, and
 *     (ii) any permission to use the Software is expressly denied.
 *
 */
package com.hds.hcp.examples;

/***
 * This is a sample for how to utilize the HCP over HTTPs REST interface.  
 * It reads the file simpleio.txt.toHCP from the local directory and writes it
 * to HCP. Then turns around and reads the object back out into file 
 * simpleio.txt.fromHCP.
 * 
 * Disclaimer: This code is only a sample and is provided for educational purposes.
 * The consumer of this sample assumes full responsibility for any effects due to
 * coding errors.
 * 
 * This sample is only compatible against HCP 5.1 and greater.
 */
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.util.EntityUtils;

import com.hds.hcp.apihelpers.HCPUtils;

public class SimpleIO {

	// Strings for the file path info.
	private static final String sBaseFileName = "simpleio.txt";
	
	// Local member variables.
	private Boolean bIsInitialized = false;
	private String sEncodedUserName, sEncodedPassword;
	private String sHCPURLFilePath;
	
	private HttpClient mHttpClient;

	/**
	 * Initialize the object by setting up internal data and establishing the HTTP client connection.
	 * 
	 * This routine is called by the ReadFromHCP and WriteToHCP routines, so calling it by the
	 * consumer of this class is unnecessary.
	 */
	void initialize(String inNamespace, String inUsername, String inPassword) throws Exception {

		if (! bIsInitialized)  // Only initialize if we haven't already
		{
			// Build the URL File Path on HCP.
			sHCPURLFilePath = "https://" + inNamespace + "/rest/examples/" + sBaseFileName;
			
			// Encode both username and password for authentication string.
			sEncodedUserName = HCPUtils.toBase64Encoding(inUsername);
			sEncodedPassword = HCPUtils.toMD5Digest(inPassword);
			
			// Get an HTTP Client setup for sample usage.
			mHttpClient = HCPUtils.initHttpClient();
			
			bIsInitialized = true;
		}
	}
	
	/**
	 * This method performs an orderly shutdown of HTTP connection manager.
	 * 
	 */
	void shutdown() throws Exception {
		// Clean up open connections by shutting down connection manager.
		mHttpClient.getConnectionManager().shutdown();
	}
	
	/**
	 * This method performs a PUT of an object data file and custom metadata
	 * file using the Whole I/O feature.
	 */
	void WriteToHCP() throws Exception {
		/*
		 * Setup the PUT request.
		 */
		HttpPut httpRequest = new HttpPut(sHCPURLFilePath);

		FileInputStream dataFile = new FileInputStream(sBaseFileName + ".toHCP");
			
		// Point the HttpRequest to the input stream.
		httpRequest.setEntity(new InputStreamEntity(dataFile, -1));

		// Set HTTP Authorization Header with HCP credentials.
		httpRequest.setHeader(HCPUtils.HTTP_AUTH_HEADER, "HCP " + sEncodedUserName + ":" + sEncodedPassword);

		/*
		 * Now execute the PUT request.
		 */
		HttpResponse httpResponse = mHttpClient.execute(httpRequest);
	        
		// For debugging purposes, dump out the HTTP Response.
		HCPUtils.dumpHttpResponse(httpResponse);
	        
		// If the return code is anything BUT 200 range indicating success, we have to throw an exception.
		if (2 != (int)(httpResponse.getStatusLine().getStatusCode() / 100))
		{
			// Clean up after ourselves and release the HTTP connection to the connection manager.
			EntityUtils.consume(httpResponse.getEntity());
			
			throw new HttpResponseException(httpResponse.getStatusLine().getStatusCode(),
					"Unexpected status returned from " + httpRequest.getMethod() + " ("
					+ httpResponse.getStatusLine().getStatusCode() + ": " 
					+ httpResponse.getStatusLine().getReasonPhrase() + ")");
		}
		
		// Clean up after ourselves and release the HTTP connection to the connection manager.
		EntityUtils.consume(httpResponse.getEntity());
	}
	
	/**
	 * This method performs a GET of a file and its custom metadata content utilizing 
	 * the Whole I/O feature.
	 */
	void ReadFromHCP() throws Exception {
		/*
		 * Setup the GET request.
		 */
		HttpGet httpRequest = new HttpGet(sHCPURLFilePath);
	
		// Set HTTP Authorization Header with HCP credentials.
		httpRequest.setHeader(HCPUtils.HTTP_AUTH_HEADER, "HCP " + sEncodedUserName + ":" + sEncodedPassword);

		/*
		 * Now execute the GET request.
		 */
		HttpResponse httpResponse = mHttpClient.execute(httpRequest);
	        
		// For debugging purposes, dump out the HTTP Response.
		HCPUtils.dumpHttpResponse(httpResponse);
	        
		// If the return code is anything BUT 200 range indicating success, we have to throw an exception.
		if (2 != (int)(httpResponse.getStatusLine().getStatusCode() / 100))
		{
			// Clean up after ourselves and release the HTTP connection to the connection manager.
			EntityUtils.consume(httpResponse.getEntity());
			
			throw new HttpResponseException(httpResponse.getStatusLine().getStatusCode(),
					"Unexpected status returned from " + httpRequest.getMethod() + " ("
					+ httpResponse.getStatusLine().getStatusCode() + ": " 
					+ httpResponse.getStatusLine().getReasonPhrase() + ")");
	    }
	        
		/*
		 * Write the content to disk.
		 */
		InputStream responseStream = httpResponse.getEntity().getContent();
		FileOutputStream dataFile = new FileOutputStream(sBaseFileName + ".fromHCP");
		
		// Keep reading bytes until EOF has been reached.
		int readSize = 0;
		byte buffer[] = new byte[2048];
		while (-1 != (readSize = responseStream.read(buffer))) {
			// Write all we just read
			dataFile.write(buffer, 0, readSize);
		}
		
		dataFile.close();

		// Clean up after ourselves and release the HTTP connection to the connection manager.
		EntityUtils.consume(httpResponse.getEntity());
	}
	
	
	/**
	 * @param args - Specification of Namespace, Username, and Password.
	 */
	public static void main(String[] args) {

		SimpleIO myClass = new SimpleIO();

		if (args.length != 3) {
			System.out.println();
			System.out.println("Usage: " + myClass.getClass().getSimpleName() + " <DNS-Namespace> <Username> <Password>\n");
			System.out.println("  where <DNS-Namespace> is the fully qualified DNS name of the HCP Namespace.");
			System.out.println("              For example: \"ns1.ten1.myhcp.example.com\"");
			System.out.println("        <Username> and <Password> are the credentials of the HCP user with data");
			System.out.println("              access permissions for the namespace.");
			System.out.println();
			
			System.exit(-1);
		}
		
		try {
			// Initialize the class with the input parameters.
			myClass.initialize(args[0], args[1], args[2]);
			
			// Write object to HCP
			myClass.WriteToHCP();
	
			// Read object from HCP
			myClass.ReadFromHCP();
			
			// Cleanup before object destruction.
			myClass.shutdown();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
